import { promises as fs } from 'fs';
import { join, relative } from 'path';
import { FileIndexItem } from '../types';
import nodePath from "node:path";

/**
 * 文件工具类
 */
export class FileUtil {
    /** 默认编码 */
    private static readonly defaultEncoding = 'utf8';
    /** 文件锁超时时间（毫秒） */
    private static readonly lockTimeout = 5000;
    /** 文件锁重试间隔（毫秒） */
    private static readonly retryInterval = 100;
    /** 路径分隔符 */
    public static readonly separator = nodePath.sep;

    /**
     * 检查路径是否存在
     * @param path 路径
     */
    static async exists(path: string): Promise<boolean> {
        try {
            await fs.access(path);
            return true;
        } catch {
            return false;
        }
    }

    /**
     * 创建目录
     * @param path 目录路径
     */
    static async createDirectory(path: string): Promise<void> {
        await fs.mkdir(path, { recursive: true });
    }

    /**
     * 获取文件信息
     * @param path 文件路径
     * @param rootPath 根路径
     */
    static async getFileInfo(path: string, rootPath: string): Promise<FileIndexItem> {
        const stat = await fs.stat(path);
        const relativePath = relative(rootPath, path);
        const title = path.split(FileUtil.separator).pop() || '';
        const id = Buffer.from(relativePath).toString('hex');
        const extension = path.includes('.') ? path.split('.').pop() || '' : '';
        
        // 构造使用ID作为文件名的相对路径
        const pathParts = relativePath.split(FileUtil.separator);
        const idBasedPath = pathParts.map((part, index) => {
            if (index === pathParts.length - 1) {
                // 最后一个部分（文件名）替换为ID
                return id + (extension ? '.' + extension : '');
            }
            return part;
        }).join(FileUtil.separator);

        return {
            id,
            title,
            extension,
            relativePath: idBasedPath,
            vRelativePath: relativePath,
            isDirectory: stat.isDirectory(),
            size: stat.size,
            createTime: stat.birthtime.getTime(),
            updateTime: stat.mtime.getTime()
        };
    }

    /**
     * 读取文件内容
     * @param path 文件路径
     */
    static async readFile(path: string): Promise<string> {
        return await fs.readFile(path, 'utf8');
    }

    /**
     * 写入文件内容
     * @param path 文件路径
     * @param content 文件内容
     */
    static async writeFile(path: string, content: string): Promise<void> {
        await fs.writeFile(path, content, 'utf8');
    }

    /**
     * 删除文件或目录
     * @param path 文件或目录路径
     * @param recursive 是否递归删除（用于目录）
     */
    static async delete(path: string, recursive = true): Promise<void> {
        const stat = await fs.stat(path);
        if (stat.isDirectory()) {
            await fs.rm(path, { recursive, force: true });
        } else {
            await fs.unlink(path);
        }
    }

    /**
     * 移动文件或目录
     * @param sourcePath 源路径
     * @param targetPath 目标路径
     */
    static async move(sourcePath: string, targetPath: string): Promise<void> {
        await fs.rename(sourcePath, targetPath);
    }

    /**
     * 复制文件或目录
     * @param sourcePath 源路径
     * @param targetPath 目标路径
     */
    static async copy(sourcePath: string, targetPath: string): Promise<void> {
        const stat = await fs.stat(sourcePath);
        if (stat.isDirectory()) {
            await fs.mkdir(targetPath, { recursive: true });
            const files = await fs.readdir(sourcePath);
            for (const file of files) {
                await this.copy(
                    join(sourcePath, file),
                    join(targetPath, file)
                );
            }
        } else {
            await fs.copyFile(sourcePath, targetPath);
        }
    }

    /**
     * 列出目录内容
     * @param path 目录路径
     * @param recursive 是否递归获取子目录内容
     */
    static async listDirectory(path: string, recursive = false): Promise<string[]> {
        const items = await fs.readdir(path);
        if (!recursive) {
            return items;
        }

        const result: string[] = [];
        for (const item of items) {
            const itemPath = join(path, item);
            const stat = await fs.stat(itemPath);
            result.push(item);
            if (stat.isDirectory()) {
                const subItems = await this.listDirectory(itemPath, true);
                result.push(...subItems.map(subItem => join(item, subItem)));
            }
        }
        return result;
    }

    /**
     * 生成临时ID
     */
    private static generateTempId(): string {
        return Buffer.from(Date.now().toString()).toString('hex');
    }

    /**
     * 从文件名中提取扩展名
     * @param name 文件名
     */
    static getExtension(name: string): string {
        return name.includes('.') ? name.split('.').pop() || '' : '';
    }

    /**
     * 生成基于路径的ID
     * @param path 路径
     */
    static generateId(path: string): string {
        return Buffer.from(path).toString('hex');
    }

    /**
     * 创建文件索引项
     * @param rootPath 根路径
     * @param filePath 文件路径
     * @param vRelativePath 虚拟相对路径
     * @param title 文件标题
     * @param size 文件大小
     * @param isDirectory 是否为目录
     */
    static createFileIndexItem(
        rootPath: string,
        filePath: string,
        vRelativePath: string,
        title: string,
        size: number,
        isDirectory: boolean
    ): FileIndexItem {
        const extension = isDirectory ? '' : this.getExtension(title);
        return {
            id: this.generateId(vRelativePath),
            title,
            extension,
            relativePath: relative(rootPath, filePath),
            vRelativePath,
            isDirectory,
            size,
            createTime: Date.now(),
            updateTime: Date.now()
        };
    }

    /**
     * 创建文件并生成索引项
     * @param rootPath 根路径
     * @param parentPath 父目录路径
     * @param parentVPath 父目录虚拟路径
     * @param name 文件名
     * @param content 文件内容
     */
    static async createFileWithIndex(
        rootPath: string,
        parentPath: string,
        parentVPath: string,
        name: string,
        content: string = ''
    ): Promise<{ path: string; indexItem: FileIndexItem }> {
        const tempId = this.generateTempId();
        const extension = this.getExtension(name);
        const tempPath = join(parentPath, tempId + (extension ? '.' + extension : ''));

        // 创建文件
        await this.writeFile(tempPath, content);

        // 构造虚拟路径和最终路径
        const vRelativePath = join(parentVPath, name);
        const id = this.generateId(vRelativePath);
        const finalPath = join(parentPath, id + (extension ? '.' + extension : ''));

        // 重命名为最终ID
        await this.move(tempPath, finalPath);

        // 创建索引项
        const indexItem = this.createFileIndexItem(
            rootPath,
            finalPath,
            vRelativePath,
            name,
            Buffer.from(content).length,
            false
        );

        return { path: finalPath, indexItem };
    }

    /**
     * 创建目录并生成索引项
     * @param rootPath 根路径
     * @param parentPath 父目录路径
     * @param parentVPath 父目录虚拟路径
     * @param name 目录名
     */
    static async createDirectoryWithIndex(
        rootPath: string,
        parentPath: string,
        parentVPath: string,
        name: string
    ): Promise<{ path: string; indexItem: FileIndexItem }> {
        const tempId = this.generateTempId();
        const tempPath = join(parentPath, tempId);

        // 创建临时目录
        await this.createDirectory(tempPath);

        // 构造虚拟路径和最终路径
        const vRelativePath = join(parentVPath, name);
        const id = this.generateId(vRelativePath);
        const finalPath = join(parentPath, id);

        // 重命名为最终ID
        await this.move(tempPath, finalPath);

        // 创建索引项
        const indexItem = this.createFileIndexItem(
            rootPath,
            finalPath,
            vRelativePath,
            name,
            0,
            true
        );

        return { path: finalPath, indexItem };
    }
}
